﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLite.Log;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using NLite.Domain.Cfg;
using NLite.Reflection;

namespace NLite.Domain.Wcf.Server
{
    public class DispatcherService : IRemoteDispatcherService,IServiceDispatcher
    {
        static readonly ILog log = LogManager.GetLogger("Wcf.Dispatcher.Server");
        internal static readonly NLite.Reflection.Func SetRequestContext = typeof(ServiceRequest).GetProperty("Context").GetSetMethod(true).GetFunc();

        public ResponseWrapper Dispatch(RequestWrapper req2)
        {

            var respWrapper = new ResponseWrapper();

            RequestBody reqBody = null;
            var fmt = new BinaryFormatter();
            if (req2.Body != null && req2.Body.Length > 0)
            {
                using (var stream = new MemoryStream(req2.Body))
                {
                    try
                    {
                        reqBody = fmt.Deserialize(stream) as RequestBody;
                    }
                    catch (Exception ex)
                    {
                        log.Error(ex.Message, ex);
                    }
                }
            }

           
            if (reqBody != null && reqBody.Data != null)
            {
                var paraDic = reqBody.Data;
                foreach (var key in paraDic.Keys)
                {
                    var value = paraDic[key] as HttpPostedFileVO[];
                    if (value != null && value.Length > 0)
                        paraDic[key] = value.Select(p => HttpPostedFileWrapper.From(p)).ToArray();
                }
            }

            var req = ServiceRequest.Create(req2.ServiceName, req2.OperationName, reqBody != null ? reqBody.Data:null);

            req.ValidateRequest = req2.ValidateRequest;

            if (reqBody != null && reqBody.Context != null)
                SetRequestContext(req,reqBody.Context);

            var resp = Dispatch(req);
            respWrapper.Success = resp.Success;

            var respBody = new ResponseBody
            {
                Data = resp.Result,
                ErrorState = resp.ErrorState,
                Exceptions = resp.Exceptions,
            };

           

            if (req.Context != null && req.Context.Count > 0)
            {
                if (req.Context.ContainsKey("ViewData"))
                {
                    var viewData = req.Context["ViewData"] as IDictionary<string, object>;
                    if (viewData == null || viewData.Count == 0)
                        req.Context.Remove("ViewData");
                }
                if (req.Context.ContainsKey("TempData"))
                {
                    var tmpData = req.Context["TempData"] as IDictionary<string, object>;
                    if (tmpData == null || tmpData.Count == 0)
                        req.Context.Remove("TempData");
                }
                if(req.Context.Count > 0)
                    respBody.Context = req.Context;
            }

            byte[] body = null;
            using (var stream = new MemoryStream())
            {
                try
                {
                    fmt.Serialize(stream, respBody);
                    body = stream.ToArray();
                }
                catch (Exception ex)
                {
                    log.Error(ex.Message, ex);
                }
            }

            
            respWrapper.Body = body;
            return respWrapper;
        }

        public IServiceResponse Dispatch(IServiceRequest req)
        {
            var dispacther = new DefaultServiceDispatcher(ServiceLocator.Get<INdfConfigurationItem>());
            return dispacther.Dispatch(req);
        }
    }
}
